/**
 * 
 */
package org.bookie.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.AccessType;
import org.hibernate.validator.NotNull;

/**
 * Class modelling an event to bet on. An event contains several {@link Wager}s
 * representing possible outcomes of this Event. Every Event has a label and can
 * be categorized. An {@link User} can place a bet on an outcome of an Event
 * only if the Event's end date is not in the past.
 * 
 * @author Igor Drobiazko
 */
@Entity
@AccessType("field")
@Table(name = "Events")
public class Event extends LabeledEntity {

	private static final long serialVersionUID = 1L;

	/** The end date of the event */
	@Basic
	@NotNull
	private Date endDate;

	/** List of all bets */
	@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, mappedBy = "event")
	private final List<Bet> bets = new ArrayList<Bet>();

	/** Category this event belongs to */
	@ManyToOne
	@JoinColumn(name = "CATEGORY_ID", nullable = false)
	private Category category;
	
	@Enumerated(EnumType.ORDINAL) @NotNull 
	private State state = State.INACTIVE;

	/**
	 * Constructs a new instance of the event.
	 * 
	 * @param label
	 *            label of the event to set
	 * @param endDate
	 *            end date to set
	 * @param category
	 *            category to set
	 */
	public Event(String label, Date endDate, Category category) {
		setLabel(label);
		this.endDate = endDate;
		this.category = category;
	}

	/** Creates an empty Event */
	protected Event() {
	}

	/**
	 * Adds a {@link Outcome} to the event
	 * 
	 * @param bet
	 *            Bet to add
	 * @return this Event
	 */
	public Event addBet(Bet... bets) {
		for (Bet next : bets) {
			getBets().add(next);
			next.setEvent(this);
		}
		return this;
	}
	
	public State getState(){
		if(state.value()==State.INACTIVE.value()) return State.INACTIVE;
		if(getEndDate().before(new Date()))return State.INACTIVE;
		return State.ACTIVE;
	}
	
	public void setState(State state){
		this.state = state;
	}

	/**
	 * Get the {@link Bet}s of the event
	 */
	public List<Bet> getBets() {
		return bets;
	}

	/**
	 * Get the {@link Category} of the event
	 * 
	 * @return instance of Category
	 */
	public Category getCategory() {
		return category;
	}

	/**
	 * Get the end date
	 * 
	 * @return instance of Date
	 */
	public Date getEndDate() {
		return endDate;
	}

	/**
	 * Returns main bet that will be used on the first page Currently returns
	 * simply first {@link Bet} from the {@link #getBets()} list or
	 * <code>null</code> is list is empty
	 * 
	 * @return
	 */
	public Bet getMainBet() {
		if (getBets().isEmpty()) {
			return null;
		}
		return getBets().iterator().next();
	}

	/**
	 * Set the {@link Category} of the event
	 * 
	 * @param category
	 *            category to set
	 */
	public void setCategory(Category category) {
		this.category = category;
		this.category.getEvents().add(this);
	}

	/**
	 * Set the end date
	 * 
	 * @param endDate
	 *            date to set
	 */
	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}
	
	public static enum State{
		INACTIVE(0), ACTIVE(1);
		private int value;
		
		private State(int value){
			this.value=value;
		}
		
		public int value(){
			return this.value;
		}
	}
}
